03. 클래스 설계: 모든 것과 연결되는 설계 기반

📌 Contents

📌 클래스 단위로 잘 동작하도록 설계하기

가장 중요한 것은 '클래스 단위로도 잘 동작하게 설계해야 한다'는 접근 방법

  • 클래스는 클래스 하나로도 잘 동작할 수 있게 설계해야 함
  • 복잡한 초기 설정을 하지 않아도 곧바로 사용할 수 있게 만들어야 함
  • 클래스를 마음대로 조작해서 클래스 전체가 고장나는 일이 없게, 최소한의 조작 방법만 외부에 제공해야 함


  • 클래스의 구성 요소
    • 인스턴스 변수
    • 메서드
  • 잘 만들어진 클래스의 구성 요소
    • 인스턴스 변수
    • 인스턴스 변수에 잘못된 값이 할당되지 않게 막고, 정상적으로 조작하는 메서드
  • 이렇게 클래스가 인스턴스 변수와 메서드를 구성 요소로 가져야 하는 이유는 데이터 클래스에서 일어나는 폐해들을 생각해보면 알 수 있음


  • 데이터 클래스는 일반적으로 인스턴스 변수를 조작하는 로직이 다른 클래스에 구현되어 있음
  • 따라서 연관성을 알아채기 어려워서 코드가 중복될 수 있고, 수정하다가 중복 코드 중 일부를 그대로 둘 수 있고, 가독성을 낮춤
  • 또한 인스턴스를 생성하더라도 인스턴스 변수들은 아직 유효하지 않은 상태이므로, 초기화를 따로 해줘야 하는데, 데이터 클래스는 초기화 작업을 하는 코드조차 다른 클래스에 구현되어 있음
  • 인스턴스 변수에 값을 잘못 넣을수도 있는데, 데이터 클래스를 잘못된 값으로부터 방어하기 위한 유효성 검사도 다른 클래스에 구현되어 있음
  • 즉, 데이터 클래스는 다른 클래스가 여러 가지를 준비해 줘야만 잘 작동하고, 혼자서는 아무것도 할 수 없는 미성숙한 클래스

Note

'따로 초기화하지 않거나 사전 준비를 하지 않으면 사용할 수 없는' 클래스와 메서드가 있다면, 누가 사용하고 싶을까요?
자신의 몸은 자신이 지켜야 합니다. 클래스 스스로 자기 방어 임무를 수행할 수 있어야 소프트웨어 품질을 높이는 데 도움이 됩니다.
소프트웨어 구성 부품이라 할 수 있는 클래스 하나하나의 품질이 뛰어나야, 소프트웨어 전체의 품질이 향상됩니다.
데이터 클래스는 모든 것을 다른 클래스에 맡겨야 했기 때문에 악마들을 불러들였습니다. 그럼 어떻게 해야 할까요? 굉장히 간단합니다.
데이터 클래스에 자기 방어 임무를 부여해서, 다른 클래스에 맡기던 일을 스스로 할 수 있게 설계하면 됩니다.

📌 성숙한 클래스로 성장시키는 설계 기법

생성자로 확실하게 정상적인 값 설정하기

  • 데이터 클래스는 디폴트 생성자(매개변수 없는 생성자)를 사용해서 인스턴스를 생성한 뒤, 인스턴스 변수에 따로 값을 할당해서 초기화
  • 이는 '로우 데이터 객체'로서 '초기화 되지 않은 상태'를 유발하는 클래스 구조
  • 이를 방지하기 위해 적절한 초기화 로직을 생성자에 구현하기 (생성자에서 초기값을 매개변수로 받아 초기화)
  • 또한 잘못된 값으로 초기화 되지 않도록 유효성 검사를 생성자 내부에 정의하기
    • 처리 범위를 벗어나는 조건을 메서드 가장 앞 부분에서 확인하는 코드를 '가드'라고 부름
    • 가드를 사용해 유효성 검사를 하면 불필요한 요소를 메서드 앞부분에서 제외할 수 있으므로 이어지는 로직이 간단해짐

계산 로직도 데이터를 가진 쪽에 구현하기

  • '데이터'와 '데이터를 조작하는 로직'이 분리되어 있는 구조를 '응집도가 낮은 구조'라고 함
  • 응집도가 낮은 구조에서는 여러 가지 문제가 발생하는데, 이를 막으려면 스스로 일을 하는 성숙한 클래스를 만들어야 함

불변 변수로 만들어서 예상하지 못한 동작 막기

  • 인스턴스 변수를 변경하는 코드는 이해하기 어려움.
  • 변수의 값이 계속 바뀌면, 값이 언제 변경되었는지, 지금 값은 무엇인지 계속 신경써야 함
  • 코드를 수정하다 '예상치 못한 부수 효과'가 쉽게 발생함
  • 이를 막기 위해 인스턴스 변수를 값을 한 번 할당하면 다시는 바꿀 수 없는 불변 변수로 만들기 -> final 수식자 사용 (Java)

변경하고 싶다면 새로운 인스턴스 만들기

  • 불변이면 아예 변경을 못한다고 생각할 수 있음
  • 변경을 할 때는 인스턴스 변수의 내용을 변경하는 것이 아닌, 변경된 값을 가진 새로운 인스턴스를 만들어서 사용하면 됨

메서드 매개변수와 지역 변수도 불변으로 만들기

  • 값이 중간에 바뀌면, 값의 변화를 추적하기 힘들기 때문에 버그를 발생시키기도 함
  • 기본적으로 매개변수는 변경하지 않는 것이 좋음 (메서드와 생성자의 매개변수도 마찬가지)
  • 지역 변수도 중간에 값을 변경하면, 값의 의미가 바뀔 수 있음
  • 매개변수와 지역 변수 모두 final을 붙여 불변으로 만들수 있음 (Java)

엉뚱한 값을 전달하지 않도록 하기

  • int, string처럼 프로그래밍 언어가 표준적으로 제공하는 자료형을 기본 자료형이라고 함
  • 기본 자료형 위주로 사용하면, 의미가 다른 값이 여러 개 있어도 모두 int 자료형이나 string 자료형으로 정의하기 쉬움
  • 독자적인 자료형을 사용하면, 의미가 다른 값을 전달할 경우 컴파일 오류가 발생할 수 있음

의미 없는 메서드 추가하지 않기

  • 나중에 필요할 줄 알고, 시스템 사양에 필요하지 않은 메서드를 '선의'로 추가했다면,
  • 이후에 누군가 무심코 사용했을 때 버그가 될 수 있음
  • 시스템 사양에 필요한 메서드만 정의하자

📌 악마 퇴치 효과 검토하기

  • 위에서 언급한 방법들처럼 인스턴스 변수를 중심으로, 인스턴스 변수가 잘못된 상태에 빠지지 않게 설계하면 악마를 퇴치할 수 있음
  • 클래스 설계란 인스턴스 변수가 잘못된 상태에 빠지지 않게 하기 위한 구조를 만드는 것
  • 같은 데이터라고 해도 메서드 매개변수, 지역 변수, static 변수로 설계했다면 악마의 공격을 방어할 수 없음
    • 인스턴스 변수이기 때문에 방어할 수 있는 것임


  • 관련된 로직이 한 곳에 모여 있는 구조는 응집도가 높은 구조라고 함
  • '데이터'와 '그 데이터를 조작하는 로직'을 하나의 클래스로 묶고, 필요한 메서드만 외부에 공개하는 것을 캡슐화라고 함

📌 프로그램 구조의 문제 해결에 도움을 주는 디자인 패턴

  • 응집도가 높은 구조로 만들거나, 잘못된 상태로부터 프로그램을 방어하는 등 프로그램의 구조를 개선하는 설계 방법을 디자인 패턴이라고 함
  • 위에서 언급한 방법들은 두 가지 디자인 패턴에 대한 내용임

완전 생성자 패턴

  • 완전 생성자는 잘못된 상태로부터 클래스를 보호하기 위한 디자인 패턴
  • 인스턴스 변수를 모두 초기화해야만 객체를 생성할 수 있게, 매개변수를 가진 생성자를 만들기
  • 생성자 내부에서는 가드를 사용해서 잘못된 값이 들어오지 않게 만들기
  • 인스턴스 변수를 불변 변수로 만들면, 생성 후에도 잘못된 상태로부터 방어할 수 있음

값 객체 패턴

  • 값을 클래스(자료형)로 나타내는 디자인 패턴
  • 애플리케이션에서 사용하는 금액, 날짜, 주문 수, 전화번호 등 다양한 값을 값 객체로 만들 수 있음
  • 이러한 값을 값 객체로 만들어서 사용하면, 각각의 값과 로직을 응집도가 높은 구조로 만들 수 있음
  • 값 객체를 사용하면 의도하지 않게 다른 값이 섞이는 상황을 원천적으로 차단할 수 있음


  • 값 객체와 완전 생성자는 얻을 수 있는 효과가 거의 비슷하므로, 일반적으로 함께 사용함
  • '값 객체 + 완전 생성자'는 객체지향 설계에서 폭넓게 사용되는 기법임
  • '값 객체 + 완전 생성자'를 활용해서 설계하면, 제약과 의도를 자료형으로 표현할 수 있으며, 안전한 코드를 작성할 수 있음
  • 애플리케이션에서 다루는 값을 값 객체로 만들어 활용하면, 여러 악마를 퇴치할 수 있음

❓ Questions

❓ 자바스크립트에서도 인스턴스 변수와 매개변수를 불변으로 만들 수 있을까?

  • 자바에서는 변수를 불변으로 만들기 위해 변수 앞에 final을 붙여준다고 한다.
  • 자바스크립트는 애초에 변수를 선언할때 타입을 이용해 선언하는 것이 아니라 const, let을 이용하여 선언해 준다.
  • 여기서 const로 선언한 변수는 불변이므로 final과 비슷하다고 볼 수 있다.
  • 하지만 이 const는 클래스의 인스턴스 변수나 매개변수 앞에 붙이지 않는다.
  • 자바스크립트에서 클래스의 인스턴스 변수를 선언할 때 this.{변수명}을 이용한다.
  • 클래스의 필드에서는 const나 let을 이용할 수 가 없다.
  • 생성자 내부에서는 이용가능하지만 const나 let을 이용하면 생성자에서만 사용이 가능한 지역변수가 되고, 다른 메서드들에서는 사용할 수가 없다.
  • 그럼 자바스크립트에서는 인스턴스 변수를 불변으로 만들 수 없는 것일까?
    • 어떻게 자바스크립트에서 클래스의 인스턴스 변수를 불변으로 만들까 찾아보았지만 별다른 방법이 없는 것 같다.
    • 그래서 자바스크립트에서 클래스를 이용할 때는 인스턴스 값을 직접 변하지 않게 하기 위해 인스턴스 변수를 private으로 선언해 클래스 외부에서는 아예 접근을 못하게하는 것이 최선의 방법인 것 같다.
    • 클래스 내부에서 변하게 하는 것은 막지 못하는것 같다.
  • 매개변수 또한 앞에 const를 붙이지 않기 때문에 불변으로 만드는 방법은 딱히 없는 것 같다.


  • c++도 궁금해서 찾아보았는데, final과 비슷한 역할로 변수를 선언할 때 앞에 const를 붙여주면 불변 변수가 된다고 한다.
  • 자바의 final에는 상속과 관련된 기능도 있기 때문에 완전히 같지는 않다고 하지만, 변수를 불변으로 만들어 준다는 점은 같다.

❓ 자바스크립트에서 값 객체 패턴을 사용할 수 있을까?

  • 자바스크립트는 동적으로 타입이 정해지는 동적 언이이다.
  • 따라서 변수를 선언할 때 타입을 정해주지 않는다.
  • 자바스크립트에서는 값 객체 패턴을 사용할 수 없다고 생각한다.
  • 하지만 타입스크립트를 사용한다면, 값 객체 패턴과 비슷하게 코드를 작성할 수 있다고 생각한다.
  • 타입스크립트에서는 number, string 등의 기본 타입 말고도 커스텀 타입을 만들어 사용할 수 있다.
  • 이를 활용하면 값 객체 패턴과 비슷하게 코드를 작성할 수 있을 것 같다.

results matching ""

    No results matching ""